package org.skydiveapplibrary.util;

import org.skydiveapplibrary.data.AltitudeUnit;
import org.skydiveapplibrary.data.FreefallProfileType;

public class FreefallTimeCalculator
{
	// constants for freefall time estimation
	private static final float VerticalTerminalVelocity = 235; // ft/sec
	private static final float HorizontalTerminalVelocity = 176; // ft/sec
	private static final float TrackingTerminalVelocity = 144; // ft/sec
	private static final float WingsuitTerminalVelocity = 73; // ft/sec
	private static final float SkysurfingTerminalVelocity = 158; // ft/sec
	private static final float Gravity = 32.174f; // ft/sec
	
	public static int calculateFreefallTime(
			FreefallProfileType profileType,
			int exitAltitude,
			int deploymentAltitude,
			AltitudeUnit altUnit)
	{
		// invalid
		if (deploymentAltitude >= exitAltitude)
		{
			return 0;
		}
		
		// get terminal velocify (ft/sec)
		float tv = getTerminalVelocity(profileType);
		
		// get time and distance to tv
		float timeToTv = tv / Gravity;
		float distToTv = 0.5f * Gravity * timeToTv * timeToTv;
		
		// get total distance in feet
		float distanceFt = AltitudeUnit.convert((exitAltitude - deploymentAltitude), altUnit, AltitudeUnit.Feet);
		
		if (distanceFt > distToTv)
		{
			float remainingTime = (distanceFt - distToTv) / tv;
			return Math.round(remainingTime + timeToTv);
		}
		else
		{
			float sqrt = (float)Math.sqrt(2 * distanceFt / Gravity);
			return Math.round(sqrt);
		}
	}
	
	private static float getTerminalVelocity(FreefallProfileType freefallProfile)
	{
		float tv = 0;
		switch (freefallProfile)
		{
			case Horizontal:
				tv = HorizontalTerminalVelocity;
				break;
			case Vertical:
				tv = VerticalTerminalVelocity;
				break;
			case Tracking:
				tv = TrackingTerminalVelocity;
				break;
			case Wingsuit:
				tv = WingsuitTerminalVelocity;
				break;
			case Skysurfing:
				tv = SkysurfingTerminalVelocity;
				break;
			default:
				tv = HorizontalTerminalVelocity;
		}
		
		return tv;
	}
}
